package com.ddpt.platform.common.util;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

public class DateUtil {

    public static final String DAY_FORMAT = "yyyy-MM-dd";

    /**
     * 获取指定毫秒数对应日期的当日开始(毫秒)
     *
     * @param dateMills 指定日期的毫秒数
     * @return
     */
    public static long getStartOfDayFromMills(long dateMills) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(dateMills));
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取指定毫秒数对应日期的当日结尾(毫秒)
     *
     * @param dateMills 指定日期的毫秒数
     * @return
     */
    public static long getEndOfDayFromMills(long dateMills) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(dateMills));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取 n 天前后的时间戳
     *
     * @param type 1-前，2-后
     * @param days 天数
     * @return 时间戳
     */
    public static Long getTimiMill(Integer type, Integer days) {

        LocalDate now = LocalDate.now();
        if (type == 1) {
            return LocalDateTime.of(now.minusDays(days), LocalTime.MIN).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        } else {
            now = now.plusDays(days);
            return LocalDateTime.of(now.plusDays(days), LocalTime.MAX).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        }
    }

    /**
     * 获取某个日期数的时间戳
     *
     * @param dates      日期数
     * @param dateType   日期类型（1日，2月）
     * @param startOrEnd 开始或结束时间（1-开始，2-结束）
     * @return 时间戳
     */
    public static Long getTimiMill(Integer dates, Integer dateType, Integer startOrEnd) {

        LocalDate now = LocalDate.now();
        if (dateType == 1) {
            now = now.plusDays(dates);
        } else {
            now = now.plusMonths(dates);
        }
        if (startOrEnd == 1) {
            return LocalDateTime.of(now, LocalTime.MIN).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        } else {
            return LocalDateTime.of(now, LocalTime.MAX).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        }
    }

    /**
     * 根据当前日期 LocalDate 获取 日、周、月第一天的时间戳(默认返回当天0点)
     *
     * @param now  当前时间
     * @param type 1日，2周，3月
     * @return 时间戳
     */
    public static Long getTimiMill(LocalDate now, Integer type) {
        type = type == null ? 1 : type;
        if (type == 3) {
            return LocalDateTime.of(now.with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN)
                    .toInstant(ZoneOffset.ofHours(8)).toEpochMilli();// 获取本月的第一天0点时间戳
        } else if (type == 2) {
            return LocalDateTime.of(now.with(DayOfWeek.MONDAY), LocalTime.MIN)
                    .toInstant(ZoneOffset.ofHours(8)).toEpochMilli();// 获取本周的第一天0点时间戳
        } else {
            return LocalDateTime.of(now, LocalTime.MIN).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();// 今天0点时间戳
        }
    }

    /**
     * 根据当前日期 LocalDate 获取 日、周、月最后一天的时间戳(当天23:59:59)
     *
     * @param now  当前时间
     * @param type 1日，2周，3月，4年
     * @return 时间戳
     */
    public static Long getEndTimiMill(LocalDate now, Integer type) {
        type = type == null ? 1 : type;
        if (type == 4) {
            return LocalDateTime.of(now.with(TemporalAdjusters.lastDayOfYear()), LocalTime.MAX)
                    .toInstant(ZoneOffset.ofHours(8)).toEpochMilli();// 获取本年最后一天23:59:59时间戳
        } else if (type == 3) {
            return LocalDateTime.of(now.with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX)
                    .toInstant(ZoneOffset.ofHours(8)).toEpochMilli();// 获取本月最后一天23:59:59时间戳
        } else if (type == 2) {
            return LocalDateTime.of(now.with(DayOfWeek.SUNDAY), LocalTime.MAX)
                    .toInstant(ZoneOffset.ofHours(8)).toEpochMilli();// 获取本周最后一天23:59:59时间戳
        } else {
            return LocalDateTime.of(now, LocalTime.MAX).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();// 今天0点时间戳
        }
    }

    /**
     * 获取某 日、周、月、年 初/末的时间戳
     *
     * @param datas      相对当前时间的相隔数
     * @param dateType   1日、2周、3月、4年
     * @param startOrEnd 0初/1末
     * @param type       1开始/2结束 时间戳
     * @return
     */
    public static Long timeMill(Integer datas, Integer dateType, Integer startOrEnd, Integer type) {

        LocalDate now = LocalDate.now();
        if (dateType == 1){
            now = now.plusDays(datas);
        } else if (dateType == 2) {
            now = now.plusWeeks(datas).with(startOrEnd == 0 ? TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY) : TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
        } else if (dateType == 3) {
            now = now.plusMonths(datas).with(startOrEnd == 0 ? TemporalAdjusters.firstDayOfMonth() : TemporalAdjusters.lastDayOfMonth());
        } else {
            now = now.plusYears(datas).with(startOrEnd == 0 ? TemporalAdjusters.firstDayOfYear() : TemporalAdjusters.lastDayOfYear());
        }

        if (1 == type) {
            return now.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        } else {
            return LocalDateTime.of(now, LocalTime.MAX).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        }
    }

    /**
     * 获取时间段内每天的时间戳
     */
    public static List<Long> getEveryDayTime(Long start, Long end) {
        List<Long> list = new ArrayList<>();
        for (long i = start; i < end; i += 86400000) {
            list.add(i);
        }
        return list;
    }

    /**
     * 获取当天零点零分零秒时间戳
     *
     * @return
     */
    public static Long getDayTimeStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long date = calendar.getTime().getTime();
        return date;
    }

    /**
     * 获取当天最后一秒时间戳
     *
     * @return
     */
    public static Long getDayTimeEnd() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 0);
        long date = calendar.getTime().getTime();
        return date;
    }

    /**
     * 获取当天零点零分零秒时间戳
     *
     * @return
     */
    public static Long getDayTimeYesStart() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24));
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long date = calendar.getTime().getTime();
        return date;
    }

    /**
     * 获取当天最后一秒时间戳
     *
     * @return
     */
    public static Long getDayTimeYesEnd() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 0);
        long date = calendar.getTime().getTime();
        return date;
    }

    /**
     * 获取本月第一天
     *
     * @param
     */
    public static Long getMonthFirstDay() throws Exception {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String startDay = df.format(new Date());

        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.parseInt(startDay.substring(0, 4)), Integer.parseInt(startDay.substring(5, 7)) - 1, 1);
        String firstDayOfMonth = new SimpleDateFormat("yyyy-MM-dd ").format(calendar.getTime());
        Calendar calendar_1 = Calendar.getInstance();
        calendar_1.setTime(df.parse(firstDayOfMonth));
        calendar_1.set(Calendar.HOUR_OF_DAY, 0);
        calendar_1.set(Calendar.MINUTE, 0);
        calendar_1.set(Calendar.SECOND, 0);
        calendar_1.set(Calendar.MILLISECOND, 0);
        return calendar_1.getTime().getTime();
    }

    /**
     * 获取本月最后一天
     *
     * @param
     */
    public static Long getMonthLastDay() throws Exception {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String startDay = df.format(new Date());

        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.parseInt(startDay.substring(0, 4)), Integer.parseInt(startDay.substring(5, 7)) - 1, 1);

        //这里先设置要获取月份的下月的第一天
        calendar.set(Integer.parseInt(startDay.substring(0, 4)), Integer.parseInt(startDay.substring(5, 7)), 1);
        //这里将日期值减去一天，从而获取到要求的月份最后一天
        calendar.add(Calendar.DATE, -1);
        Calendar calendar_1 = Calendar.getInstance();
        String lastDayOfMonth = new SimpleDateFormat("yyyy-MM-dd ").format(calendar.getTime());
        calendar_1.setTime(df.parse(lastDayOfMonth));
        calendar_1.set(Calendar.HOUR_OF_DAY, 23);
        calendar_1.set(Calendar.MINUTE, 59);
        calendar_1.set(Calendar.SECOND, 59);
        calendar_1.set(Calendar.MILLISECOND, 0);

        return calendar_1.getTime().getTime();
    }

    /**
     * 根据当前日期获取本季度第一天
     **/
    public static Long getCurrentQuarterStartTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;
        SimpleDateFormat longSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = null;
        try {
            if (currentMonth <= 3)
                c.set(Calendar.MONTH, 0);
            else if (currentMonth <= 6)
                c.set(Calendar.MONTH, 3);
            else if (currentMonth <= 9)
                c.set(Calendar.MONTH, 6);
            else if (currentMonth <= 12)
                c.set(Calendar.MONTH, 9);
            c.set(Calendar.DATE, 1);
            now = longSdf.parse(shortSdf.format(c.getTime()) + " 00:00:00");
            Calendar calendar_1 = Calendar.getInstance();
            calendar_1.setTime(now);
            calendar_1.set(Calendar.HOUR_OF_DAY, 0);
            calendar_1.set(Calendar.MINUTE, 0);
            calendar_1.set(Calendar.SECOND, 0);
            calendar_1.set(Calendar.MILLISECOND, 0);
            return calendar_1.getTime().getTime();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取时间失败");
        }

    }

    /**
     * 根据当前日期获取本季度最后一天
     **/
    public static Long getCurrentQuarterEndTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;
        SimpleDateFormat longSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd");
        Date now = null;
        try {
            if (currentMonth <= 3)
                c.set(Calendar.MONTH, 0);
            else if (currentMonth <= 6)
                c.set(Calendar.MONTH, 3);
            else if (currentMonth <= 9)
                c.set(Calendar.MONTH, 6);
            else if (currentMonth <= 12)
                c.set(Calendar.MONTH, 9);
            c.set(Calendar.DATE, 1);
            now = longSdf.parse(shortSdf.format(c.getTime()) + " 00:00:00");
            Calendar cal = Calendar.getInstance();
            cal.setTime(now);
            cal.add(Calendar.MONTH, 2);
            cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
            cal.set(Calendar.HOUR_OF_DAY, 23);
            cal.set(Calendar.MINUTE, 59);
            cal.set(Calendar.SECOND, 59);
            cal.set(Calendar.MILLISECOND, 0);
            return cal.getTime().getTime();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取时间失败");
        }

    }


    private static String datePattern = "yyyy-MM-dd";

    /**
     * 时间转时间字符串
     *
     * @param date    日期
     * @param pattern 格式
     * @return String
     */
    public static String format(Date date, String pattern) {
        if (date == null)
            return "";
        return DateFormatUtils.format(date, pattern);
    }

    /**
     * 时间转时间字符串为yyyy-MM-dd HH:mm:ss 格式
     *
     * @param date 日期
     * @return String
     */
    public static String formatDateTime(Date date) {
        if (date == null)
            return "";
        return DateFormatUtils.format(date, datePattern);
    }


    /**
     * 时间字符串转化为yyyy-MM-dd HH:mm:ss 格式
     *
     * @param str 日期
     * @return Date
     */
    public static Date parseDateTime(String str) {
        if (str == null)
            return null;
        try {
            return DateUtils.parseDate(str, datePattern);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串转时间
     *
     * @param str             字符串
     * @param dateTimePattern 格式
     * @return Date
     */
    public static Date parseDateTime(String str, String dateTimePattern) {
        if (str == null)
            return null;
        try {
            return DateUtils.parseDate(str, Locale.CHINESE, dateTimePattern);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 获取当年的第一天
     */
    public static Long getCurrentFirstOfYear() {
        Calendar currCal = Calendar.getInstance();
        int currentYear = currCal.get(Calendar.YEAR);
        Calendar calendar_1 = Calendar.getInstance();
        calendar_1.setTime(getFirstOfYear(currentYear));
        calendar_1.set(Calendar.HOUR_OF_DAY, 0);
        calendar_1.set(Calendar.MINUTE, 0);
        calendar_1.set(Calendar.SECOND, 0);
        calendar_1.set(Calendar.MILLISECOND, 0);
        return calendar_1.getTime().getTime();
    }

    /**
     * 获取当年的最后一天
     */
    public static Long getCurrentLastOfYear() {
        Calendar currCal = Calendar.getInstance();
        int currentYear = currCal.get(Calendar.YEAR);
        Calendar cal = Calendar.getInstance();
        cal.setTime(getLastOfYear(currentYear));
        cal.add(Calendar.MONTH, 2);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime().getTime();
    }

    /**
     * 获取某年第一天日期
     *
     * @param year 年份
     * @return Date
     */
    public static Date getFirstOfYear(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        return calendar.getTime();
    }


    /**
     * 获取某年最后一天日期
     *
     * @param year 年份
     * @return Date
     */
    public static Date getLastOfYear(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        return calendar.getTime();
    }


    /**
     * 获取某月第一天
     *
     * @param
     */
    public static Long getMonthFirstDay(Date date) throws Exception {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String startDay = df.format(date);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.parseInt(startDay.substring(0, 4)), Integer.parseInt(startDay.substring(5, 7)) - 1, 1);
        String firstDayOfMonth = new SimpleDateFormat("yyyy-MM-dd ").format(calendar.getTime());
        Calendar calendar_1 = Calendar.getInstance();
        calendar_1.setTime(df.parse(firstDayOfMonth));
        calendar_1.set(Calendar.HOUR_OF_DAY, 0);
        calendar_1.set(Calendar.MINUTE, 0);
        calendar_1.set(Calendar.SECOND, 0);
        calendar_1.set(Calendar.MILLISECOND, 0);
        return calendar_1.getTime().getTime();
    }

    /**
     * 获取某月最后一天
     *
     * @param
     */
    public static Long getMonthLastDay(Date date) throws Exception {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String startDay = df.format(date);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.parseInt(startDay.substring(0, 4)), Integer.parseInt(startDay.substring(5, 7)) - 1, 1);

        //这里先设置要获取月份的下月的第一天
        calendar.set(Integer.parseInt(startDay.substring(0, 4)), Integer.parseInt(startDay.substring(5, 7)), 1);
        //这里将日期值减去一天，从而获取到要求的月份最后一天
        calendar.add(Calendar.DATE, -1);
        Calendar calendar_1 = Calendar.getInstance();
        String lastDayOfMonth = new SimpleDateFormat("yyyy-MM-dd ").format(calendar.getTime());
        calendar_1.setTime(df.parse(lastDayOfMonth));
        calendar_1.set(Calendar.HOUR_OF_DAY, 23);
        calendar_1.set(Calendar.MINUTE, 59);
        calendar_1.set(Calendar.SECOND, 59);
        calendar_1.set(Calendar.MILLISECOND, 0);

        return calendar_1.getTime().getTime();
    }

    public static String format(Long time, String strFormat) {
        DateFormat df = new SimpleDateFormat(strFormat);
        String str = df.format(time);
        return str;
    }

    /**
     * 获取时间段内所有的周  单个数据格式（"weekStart-weekEnd"）
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static List<String> groupByWeek(String startTime, String endTime) {
        // 时间格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 将字符串转为 LocalDateTime
        LocalDateTime end = LocalDateTime.parse(endTime, formatter);
        LocalDateTime start = LocalDateTime.parse(startTime, formatter);

        // 获取开始时间和结束时间的日期和时间部分
        LocalTime startTimeOfDay = start.toLocalTime();
        LocalDate endDate = end.toLocalDate();
        LocalTime endTimeOfDay = end.toLocalTime();
        LocalDate startDate = start.toLocalDate();

        // 计算总共有多少周
        int numberOfWeeks = (int) ChronoUnit.WEEKS.between(startDate, endDate);

        // 初始化结果列表
        List<String> resultList = new ArrayList<>(numberOfWeeks);

        // 循环计算每一周的时间段
        for (int i = 0; i <= numberOfWeeks; i++) {
            // 每一周的开始时间和结束时间（按周日作为一个星期的开始）
            LocalDate weekStart = startDate.with(DayOfWeek.MONDAY).plusDays(i * 7);
            LocalDate weekEnd = weekStart.plusDays(6);

            LocalDateTime startOfWeek = LocalDateTime.of(weekStart, startTimeOfDay);
            LocalDateTime endOfWeek = LocalDateTime.of(weekEnd, endTimeOfDay);

            // 如果本周的结束时间超过了给定的结束时间，则将本周结束时间设为给定的结束时间
            if (endOfWeek.isAfter(end)) {
                endOfWeek = LocalDateTime.of(endDate, endTimeOfDay);
            }

            // 将本周时间区间加入结果列表
            resultList.add(startOfWeek.format(formatter) + "=" + endOfWeek.format(formatter));
        }

        return resultList;
    }


    /**
     * 获取两个日期之间的所有月份 (年月)
     *
     * @param startTime
     * @param endTime
     * @return：YYYY-MM
     */
    public static List<String> getMonthBetweenDate(String startTime, String endTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        // 声明保存日期集合
        List<String> list = new ArrayList<String>();
        try {
            // 转化成日期类型
            Date startDate = sdf.parse(startTime);
            Date endDate = sdf.parse(endTime);

            //用Calendar 进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            while (startDate.getTime() <= endDate.getTime()) {
                // 把日期添加到集合
                list.add(sdf.format(startDate));
                // 设置日期
                calendar.setTime(startDate);
                //把日期增加一天
                calendar.add(Calendar.MONTH, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return list;
    }


    public static void main(String[] args) {
        System.out.println(getDayTimeEnd());
    }
}
